package cloud.dao;

import cloud.beans.Anime;
import cloud.beans.Review;
import cloud.config.CacheController;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

import com.google.appengine.api.datastore.DatastoreFailureException;
import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.EntityNotFoundException;
import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Text;
import com.google.appengine.api.taskqueue.Queue;
import com.google.appengine.api.taskqueue.QueueFactory;
import com.google.appengine.api.taskqueue.TaskOptions;
import com.google.appengine.api.datastore.Transaction;

/**
 * Classe implémentant l'interface UtilisateurDao @see {@link ReviewDao}
 * @author Alexis JULIEN & R&eacute;mi OGNARD pour TERCA
 * @version 1.0
 */
public class ReviewDao {
	
	/**
	 * L'objet permettant de faire le lien avec la table.
	 */
	private DatastoreService datastore;
	
	
	/**
	 * Emsemble des erreurs produites.
	 */
	private ArrayList<String> erreursDAO;

	
	public ReviewDao() {
		
		this.datastore = DatastoreServiceFactory.getDatastoreService();
		erreursDAO = new ArrayList<String>();
	}
		
	/** Implémentation de la méthode définie dans l'interface UtilisateurDao 
	 * @see {@link AnimeDao#creer(Utilisateur)}
	*/
	public boolean creer( Review review ) throws DAOException {
		
		//create Entity type "Anime"
		Entity reviewEntity = new Entity("Review");
		
		//set Entity properties to Anime
		reviewEntity.setProperty("score", review.getScore());
		reviewEntity.setProperty("review", new Text(review.getReview()));
		reviewEntity.setProperty("userName", review.getUserName());
		reviewEntity.setProperty("date", review.getDate());
		reviewEntity.setProperty("anime_id", review.getAnime_id());		
		
		//save Entity to the datastore
		Queue queue = QueueFactory.getDefaultQueue();
		try {
			Transaction tx = datastore.beginTransaction();
			datastore.put(reviewEntity);
			TaskOptions options = TaskOptions.Builder.withUrl("/emailNewReview")
									.param("userName", review.getUserName());
			queue.add(options);
			tx.commit();
		} catch (DatastoreFailureException e){
			
		} finally {
			
		}
		//save Entity in MemCache
		CacheController.put("review", review);
		
		return true;
	}
	
	/* Implémentation de la méthode définie dans l'interface UtilisateurDao */
    public Review trouver( long id ) {

    	Review review = new Review();
		
    	//gets the Object in MemCache if it exists
    	if(CacheController.containsKey(id)) {
    		System.out.println("recupere dans le cache");
    		review = (Review) CacheController.get(id);
    	}
    	
    	//else gets the Object in Datastore 
    	else {
    		System.out.println("recupere dans le datastore");
	    	try {
	    		Key key = KeyFactory.createKey("Review", id);
	    		Entity result = datastore.get(key);
	    		review = map( result );

    	    	//save Entity to the MemCache
    	    	CacheController.put(result.getKey().getId(), review);
	    	}
	    	 catch ( SQLException | EntityNotFoundException e ) {
				erreursDAO.add( e.getMessage() );
			}
    	}
    	return review;
    }

	/* Implémentation de la méthode définie dans l'interface UtilisateurDao */
    public List<Review> lister( long id ) {
    	
    	List<Review> reviewList = new ArrayList<Review>();
    	Review review;
    		
    	try {
    		Query query = new Query("Review").setFilter(new Query.FilterPredicate("anime_id", Query.FilterOperator.EQUAL, id));
	    	List<Entity> results = datastore.prepare(query).asList(FetchOptions.Builder.withDefaults());  	
	    	
	    	for(Entity result : results){    		
	    		review = map(result);
	    		//save Entity to the MemCache
	    		CacheController.put(result.getKey().getId(), review);
	    		reviewList.add(review);
	    	}
    	}
    	 catch ( SQLException e ) {
 			erreursDAO.add( e.getMessage() );
 		}
	    	
	    return reviewList;
    } 
	
	/**
	* Simple méthode utilitaire permettant de faire la correspondance (le
	* mapping) entre une ligne issue de la table des utilisateurs (un
	* ResultSet) et un bean Utilisateur.
	*/
	private static Review map( Entity result ) throws SQLException {
		
		Review review = new Review();

		review.setId( result.getKey().getId() );
		review.setUserName( (String) result.getProperty( "userName" ) );
		review.setScore( new Integer(result.getProperty("score").toString()) );	
		Text text = (Text) result.getProperty("review");
		review.setReview( text.getValue() );
		review.setDate( (Date) result.getProperty( "date" ) );
		review.setAnime_id( (long) result.getProperty( "anime_id" ) );

		return review;
	}

}
